package controllers

import (
    "gouniapp/configs"
	"net/http"
	"net/url"
    "strings"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"gorm.io/gorm"
	"encoding/json"
	"regexp"
	"math"
	"strconv"
	"time"
	"fmt"
	"io"
	"os"
)

//调用腾讯地图逆地理编码 API 将经纬度转换为地址
func MaptoAddress(c *gin.Context) {
    type Mapdata struct {
    	Latitude  float64 `json:"latitude"`
    	Longitude float64 `json:"longitude"`
    }
    type TencentMapResponse struct {
    	Status  int     `json:"status"`
    	Message string  `json:"message"`
    	Result struct {
    		Address string `json:"address"`
    	} `json:"result"`
    }
	var jsons Mapdata
	if err := c.ShouldBindJSON(&jsons); err != nil {
	    fmt.Println("json解析错误", err)
	    JsonResponse(c, http.StatusBadRequest, "json解析错误", nil)
		return
	}
    key := "PEEBZ-RG2W3-V6H3Y-36KZS-6R3Q2-QJBFT" // 你的腾讯地图 API 密钥
    if jsons.Latitude == 0.0 || jsons.Longitude == 0.0 {
        JsonResponse(c, http.StatusBadRequest, "经纬度为空", nil)
        return
    }
    // 构造请求 URL
    apiUrl := fmt.Sprintf("https://apis.map.qq.com/ws/geocoder/v1/?location=%f,%f&key=%s", jsons.Latitude, jsons.Longitude, key)
    resp, err := http.Get(apiUrl)
    if err != nil {
        JsonResponse(c, http.StatusBadRequest, err.Error(), nil)
        return
    }
    defer resp.Body.Close()
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        JsonResponse(c, http.StatusBadRequest, err.Error(), nil)
        return
    }
    // 解析响应的 JSON 数据
	var apiResponse TencentMapResponse
	err = json.Unmarshal(body, &apiResponse)
	if err != nil {
	    JsonResponse(c, http.StatusBadRequest, "解析腾讯地图API响应失败", nil)
		return
	}
	// 检查响应的状态码
	if apiResponse.Status != 0 {
	    JsonResponse(c, http.StatusBadRequest, apiResponse.Message, nil)
		return
	}
    JsonResponse(c, http.StatusOK, "获取成功", apiResponse.Result.Address)
}

type Ldxdata struct {
	ID     uint                 `json:"id"`     // 联动表项目id
	Fh     string               `json:"fh"`     // 返回列
	Max    int                  `json:"max"`     // 总级数
	Now    int                  `json:"now"`     // 当前级
	Values map[string]string    `json:"values"`  // 联动键值对
}

// 联动下拉选项获取
func Getldoptions(c *gin.Context) {
	var req Ldxdata
	if err := c.ShouldBindJSON(&req); err != nil {
		JsonResponse(c, http.StatusBadRequest, "请求参数格式错误", nil)
		return
	}
	// 参数有效性校验
	if req.ID < 1 || req.Fh == "" {
		JsonResponse(c, http.StatusBadRequest, "必须提供联动表项目id和返回列", nil)
		return
	}
	if req.Max < 2 || req.Now < 1 || req.Now > req.Max {
		JsonResponse(c, http.StatusBadRequest, 
			fmt.Sprintf("级数参数无效(总级数:%d 当前级:%d)", req.Max, req.Now), 
			nil)
		return
	}
	// 检查联动表项目是否存在
	bgsx, err := GetFormSchema(req.ID)
	if err != nil {
		JsonResponse(c, http.StatusInternalServerError, "联动表项目不存在", nil)
		return
	}
	// 清理空值查询条件
	cleanValues := make(map[string]interface{})
	for k, v := range req.Values {
		if v != "" {
			cleanValues[k] = v
		}
	}
	// 执行数据库查询
	var results []string
	query := configs.DB.Table(bgsx.TableName).Distinct()
	if req.Now > 1 && len(cleanValues) > 0 {
		query = query.Where(cleanValues)
	}
	if err := query.Pluck(req.Fh, &results).Error; err != nil {
		JsonResponse(c, http.StatusInternalServerError, "数据查询失败", nil)
		return
	}
	JsonResponse(c, http.StatusOK, "获取成功", results)
}

type TableListResponse struct {
	Items []map[string]interface{} `json:"items"` // 动态字段数据
	Total int64                    `json:"total"` // 数据总数
}

type FilterItem struct {
	Operator string `json:"operator"` // 操作符
	Value    string `json:"value"`    // 值
}

// 分页获取表格数据
func GetTable(c *gin.Context) {
	var query struct {
		TableName   string      `json:"tablename"`
		Cxtj        []string    `json:"cxtj"`
		Page        int         `json:"page"`
		PageSize    int         `json:"pageSize"`
		Search      string      `json:"search"`
		FilterForm  map[string]FilterItem `json:"filter"`   //高级筛选
        SortField   string      `json:"sortField"`          // 排序字段
        SortOrder   string      `json:"sortOrder"`          // 排序方向
        SortType    string      `json:"sortType"`           // 排序类型
	}
	if err := c.ShouldBindJSON(&query); err != nil {
		JsonResponse(c, http.StatusBadRequest, "参数错误", nil)
		return
	}
    currentUser := GetCurrentUser(c)
    if currentUser == nil {
        JsonResponse(c, http.StatusUnauthorized, "请先登录", nil)
        return
    }
    // 限制最大每页数量
    if query.PageSize > 100 {
        query.PageSize = 100
    }
	cx := configs.DB.Table(query.TableName)
   // 验证排序字段合法性 字母数字下划线
    isValidField := func(field string) bool {
        matched, _ := regexp.MatchString("^[a-zA-Z0-9_]+$", field)
        return matched
    }
    // 处理排序逻辑
    if query.SortField != "" && query.SortOrder != "" && query.SortType != "" {
        // 验证字段合法性
        if !isValidField(query.SortField) {
            JsonResponse(c, http.StatusBadRequest, "非法排序字段", nil)
            return
        }
        // 验证排序方向
        upperOrder := strings.ToUpper(query.SortOrder)
        if upperOrder != "ASC" && upperOrder != "DESC" {
            JsonResponse(c, http.StatusBadRequest, "排序方向必须为asc或desc", nil)
            return
        }
        // 智能排序处理
        var sortExpr string
        switch query.SortType {
        case "number":
            // 通用数字排序（支持整数、小数、科学计数法）
            sortExpr = fmt.Sprintf(`
                CASE 
                    WHEN %s REGEXP '^[[:space:]]*[-+]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+)?[[:space:]]*$' 
                    THEN CAST(TRIM(%s) AS DECIMAL(30,10)) 
                    ELSE 
                        CASE WHEN "%s" = 'ASC' THEN 1 ELSE -1 END * POW(10, 308)
                END %s`,
                query.SortField,
                query.SortField,
                upperOrder,
                upperOrder)
        case "date":
            // 日期类型排序（格式：YYYY-MM-DD）
            sortExpr = fmt.Sprintf("DATE(%s) %s", query.SortField, upperOrder)
        case "datetime":
            // 日期时间原生排序（假设字段本身是时间戳类型）
            sortExpr = fmt.Sprintf("%s %s", query.SortField, upperOrder)
        default:
            // 文本排序（使用自然语言排序规则）
            sortExpr = fmt.Sprintf("%s COLLATE utf8mb4_unicode_ci %s", query.SortField, upperOrder)
        }
        cx = cx.Order(sortExpr)
    } else {
        cx.Order("id DESC") // 默认排序（当没有排序参数时）
    }
    if currentUser.Role != "admin" && currentUser.Role != "xmgly"{
	    cx.Where("cjz", currentUser.ID)
	}
	// 如果有搜索条件，添加LIKE查询
    if query.Search != "" {
        searchPattern := "%" + query.Search + "%"
        orClauses := make([]string, 0, len(query.Cxtj))
        params := make([]interface{}, 0, len(query.Cxtj))
        for _, tj := range query.Cxtj {
            orClauses = append(orClauses, "LOWER("+tj+") LIKE ?")
            params = append(params, strings.ToLower(searchPattern))
        }
        cx.Where(strings.Join(orClauses, " OR "), params...)
    }
	//是否有筛选
	if len(query.FilterForm) > 0 {
        for key, item := range query.FilterForm {
            switch item.Operator {
                case "=":
                    cx.Where(key + " = ?", item.Value)
                case "!=":
                    cx.Where(key + " != ?", item.Value)
                case ">":
                    cx.Where(key + " > ?", item.Value)
                case "<":
                    cx.Where(key + " < ?", item.Value)
                case ">=":
                    cx.Where(key + " >= ?", item.Value)
                case "<=":
                    cx.Where(key + " <= ?", item.Value)
                case "in", "noin":
                    var values []string
                    err := json.Unmarshal([]byte(item.Value), &values)
                    if err != nil {
                        JsonResponse(c, http.StatusInternalServerError, "筛选参数错误", nil)
                        return
                    }
                    if item.Operator == "in" {
                        cx.Where(key + " IN (?)", values)
                    } else {
                        cx.Where(key + " NOT IN (?)", values)
                    }
                case "startend":
                    start, end, layout, err := ParseDateRange(item.Value)
                    if err != "" {
                        JsonResponse(c, http.StatusInternalServerError, err, nil)
                        return
                    }
                    fmt.Println(start, end, layout)
                    cx.Where(key + " >= ?", start.Format(layout)).Where(key + " <= ?", end.Format(layout))
            }
        }
	}
	var total int64
	if err := cx.Count(&total).Error; err != nil {
        JsonResponse(c, http.StatusInternalServerError, "获取总数失败", nil)
        return
    }
	var result []map[string]interface{}
	if err := cx.Scopes(configs.Paginate(query.Page, query.PageSize)).Find(&result).Error; err != nil {
		JsonResponse(c, http.StatusInternalServerError, "数据查询失败", nil)
		return
	}
	JsonResponse(c, http.StatusOK, "获取成功", TableListResponse{
		Items: result,
		Total: total,
	})
}

//验证时间范围筛选
func ParseDateRange(dateRange string) (time.Time, time.Time, string, string) {
    dateRange = strings.Replace(dateRange, ".", "-", -1)
	values := strings.Split(dateRange, "/")
	if len(values) != 2 {
		return time.Time{}, time.Time{}, "", "时间范围格式错误"
	}
	layout := ""
    if strings.Contains(values[0], " ") {
        layout = "2006-01-02 15:04:05"  //日期格式为带时间的格式
    } else {
        layout = "2006-01-02"
    }
	start, err := time.Parse(layout, values[0])
    if err != nil {
        fmt.Println(err)
        return time.Time{}, time.Time{}, "", "筛选开始时间格式错误"
	}
	end, err := time.Parse(layout, values[1])
	if err != nil {
	    fmt.Println(err)
		return time.Time{}, time.Time{}, "", "筛选结束时间格式错误"
	}
	return start, end, layout, ""
}

const (
	StatusInvalidParams   = "参数错误"
	StatusNotFound        = "查询不存在"
	StatusInternalError   = "内部错误"
	StatusInvalidImage    = "图片无效"
	StatusInvalidImageFmt = "图片格式无效"
	StatusNoFieldsToUpdate = "没有可更新的字段"
	StatusCreateSuccess   = "新增成功"
	StatusUpdateSuccess   = "更新成功"
	StatusCreateFailed    = "新增失败"
	StatusUpdateFailed    = "更新失败"
)
type RowData struct {
	Tid     uint                   `json:"tid"`     // 等于0是新增，大于是行id
	ID      uint                   `json:"id"`      // 项目id
	Userid  uint                   `json:"userid"`  // 用户id，暂时不用
	Row     map[string]interface{} `json:"row"`     // 查询条件
	Input   map[string]interface{} `json:"input"`   // 查询条件
}

// 添加或修改数据接口
func AddOreditRow(c *gin.Context) {
	var rowdata RowData
	if err := c.ShouldBindJSON(&rowdata); err != nil {
		JsonResponse(c, http.StatusBadRequest, StatusInvalidParams, nil)
		return
	}
	bgsx, err := GetFormSchema(rowdata.ID)
	if err != nil {
		JsonResponse(c, http.StatusNotFound, StatusNotFound, nil)
		return
	}
	_, err = getOldData(bgsx, rowdata.Tid)
	if err != nil {
		JsonResponse(c, http.StatusInternalServerError, "数据不存在", nil)
		return
	}
	zdsz, err := configs.ParseFieldConfig(bgsx.Fields)
	if err != nil {
		JsonResponse(c, http.StatusInternalServerError, "字段属性解析错误", nil)
		return
	}
	if err := ValidateFields(rowdata.Row, zdsz, configs.MyURL); err != nil {
		JsonResponse(c, http.StatusInternalServerError, err.Error(), nil)
		return
	}
	currentUser := GetCurrentUser(c) //如果二维码没有填报员信息，则用当前登录用户id
	if currentUser != nil {
	    if cjzValue, exists := rowdata.Row["cjz"]; !exists || !IsValidCjz(cjzValue) {
            rowdata.Row["cjz"] = currentUser.ID  // 记录填报人
        }
	}
	response, code, msg := AddOrupdate(bgsx, rowdata.Row, rowdata.Tid, zdsz, currentUser)
	JsonResponse(c, code, msg, response)
}

// 辅助函数：校验cjz是否为有效的非零值
func IsValidCjz(value interface{}) bool {
    switch v := value.(type) {
    case uint:
        return v > 0
    case int:
        return v > 0
    case float64:  // JSON默认解析数字为float64
        return v > 0 && math.Trunc(v) == v  // 确保是整数
    case string:
        if num, err := strconv.ParseUint(v, 10, 64); err == nil {
            return num > 0
        }
        return false
    default:
        return false  // 其他类型（如nil）视为无效
    }
}

// 获取旧数据
func getOldData(bgsx configs.FormSchema, tid uint) (map[string]interface{}, error) {
	if tid == 0 {
		return nil, nil
	}
	var olddata map[string]interface{}
	if err := configs.DB.Table(bgsx.TableName).Where("id = ?", tid).Scan(&olddata).Error; err != nil {
		return nil, err
	}
	return olddata, nil
}

// 校验字段属性
func ValidateFields(row map[string]interface{}, zdsz map[string]configs.FieldConfig, Myurl string) error {
	for k, v := range zdsz {
		fieldValue, exists := row[k]
		if !exists {
			continue
		}
		if v.Required && (fieldValue == nil || fieldValue == "") {
			return fmt.Errorf(v.Placeholder)
		}
		if v.Required {
			switch v.Type {
			case "image":
				if err := validateImage(fieldValue, Myurl, v.Name); err != nil {
					return err
				}
			case "multiimage":
				if err := validateMultiImage(fieldValue, Myurl, v.Name); err != nil {
					return err
				}
			}
		}
	}
	return nil
}

// 校验单图
func validateImage(fieldValue interface{}, Myurl, fieldName string) error {
	fieldStr, ok := fieldValue.(string)
	if !ok || fieldStr == "" {
		return nil
	}
	decodedPath, err := url.QueryUnescape(fieldStr)
	if err != nil {
		return fmt.Errorf("%s图片无效", fieldName)
	}
	imagePath := strings.TrimPrefix(decodedPath, Myurl)
	if _, err := os.Stat(imagePath); err != nil {
		return fmt.Errorf("%s图片无效", fieldName)
	}
	return nil
}

// 校验多图
func validateMultiImage(fieldValue interface{}, Myurl, fieldName string) error {
	fieldStr, ok := fieldValue.(string)
	if !ok || fieldStr == "" {
		return nil
	}
	var imagePaths []string
	if err := json.Unmarshal([]byte(fieldStr), &imagePaths); err != nil {
		return fmt.Errorf("%s图片格式无效", fieldName)
	}
	for _, imagePath := range imagePaths {
		decodedPath, err := url.QueryUnescape(imagePath)
		if err != nil {
			return fmt.Errorf("%s图片无效", fieldName)
		}
		imagePath = strings.TrimPrefix(decodedPath, Myurl)
		if _, err := os.Stat(imagePath); err != nil {
			return fmt.Errorf("%s图片无效", fieldName)
		}
	}
	return nil
}

// 删除行
func DelRow(c *gin.Context) {
    var rows struct {
        IDS []uint `json:"ids" binding:"required,min=1"`
        ID  uint   `json:"id" binding:"required`
    }
    // 绑定请求数据
    if err := c.ShouldBindJSON(&rows); err != nil {
        fmt.Println(err)
        JsonResponse(c, http.StatusBadRequest, "参数错误", nil)
        return
    }
    if len(rows.IDS) == 0 {
        JsonResponse(c, http.StatusBadRequest, "数据不存在", nil) // 返回 400 错误码
        return
    }
    var bgsx configs.FormSchema
    if err := configs.DB.Where("id = ?", rows.ID).First(&bgsx).Error; err != nil {
        JsonResponse(c, http.StatusNotFound, "查询不存在", nil)
        return
    }
    // 开启事务
    err := configs.DB.Transaction(func(tx *gorm.DB) error {
        // 1. 删除审批记录
        if err := tx.Where("instance_id IN (SELECT id FROM process_instances WHERE data_id IN ?)", rows.IDS).
            Delete(&configs.ApprovalRecord{}).Error; err != nil {
            return err
        }

        // 2. 删除流程实例
        if err := tx.Where("data_id IN ?", rows.IDS).
            Delete(&configs.ProcessInstance{}).Error; err != nil {
            return err
        }

        // 3. 删除业务数据
        return tx.Table(bgsx.TableName).Where("id IN ?", rows.IDS).Delete(nil).Error
    })
    if err != nil {
        JsonResponse(c, http.StatusInternalServerError, "删除失败", nil)
        return
    }
    JsonResponse(c, http.StatusOK, "删除成功", rows.IDS)
}

// 清空全表数据
func Qksj(c *gin.Context) {
    bm := c.Param("bm")
    if bm == "" || bm == "form_schemas" || bm == "users" {
        JsonResponse(c, http.StatusNotFound, "表名不存在或禁止删除", nil)
        return
    }
    // 检查表是否存在
    exist := configs.DB.Migrator().HasTable(bm)
    if !exist {
        JsonResponse(c, http.StatusNotFound, "数据表不存在", nil)
        return
    }
    if err := configs.DB.Exec("truncate table " + bm).Error; err != nil {
        JsonResponse(c, http.StatusInternalServerError, "清空失败", nil)
        return
    }
    JsonResponse(c, http.StatusOK, "清空完成", nil)
}

// 异步导出表格---------------------------------------------------------------------------------------
type GtableDc struct {
	Bm          string      `json:"bm"`
	Lx          string      `json:"lx"`
	Max         int         `json:"max"`
	IDS         []uint      `json:"ids"`
	Zds         []string    `json:"zds"`
	Zd          map[string]interface{} `json:"zd"`
	FilterForm  map[string]FilterItem `json:"filter"` //高级筛选
}

// 分批读取流式写入excel，完成后返回下载链接
func OutExcel(c *gin.Context) {
    var data GtableDc
    if err := c.ShouldBindJSON(&data); err != nil {
    	JsonResponse(c, http.StatusBadRequest, "参数错误", nil)
    	return
    }
    if data.Bm == "" || data.Max < 1 {
        JsonResponse(c, http.StatusBadRequest, "参数不完整", nil)
    	return
    }
    if data.Lx == "selected" && len(data.IDS) == 0 {
        JsonResponse(c, http.StatusBadRequest, "请先选择表格行", nil)
        return
    } else if data.Lx == "filter" && len(data.FilterForm) == 0 {
        JsonResponse(c, http.StatusBadRequest, "请先点击高级筛选", nil)
        return
    }
    var bgsx configs.FormSchema
    if err := configs.DB.Where("tablename = ?", data.Bm).First(&bgsx).Error; err != nil {
        JsonResponse(c, http.StatusNotFound, "查询表不存在", nil)
        return
    }
    var zdsz map[string]configs.FieldConfig
    if err := json.Unmarshal([]byte(bgsx.Fields), &zdsz); err != nil {
        JsonResponse(c, http.StatusInternalServerError, "项目Fields参数错误", nil)
        return
    }
    response := configs.RandString(10) //随机字符用于key 和文件名
	pageSize := 1000           //每1000行为一组读取，注意最大1000
	go WriteExcel(bgsx, data, response, pageSize, zdsz)
	JsonResponse(c, http.StatusOK, "创建excel文件成功", response)
}

// 图片信息结构
type ImageInfo struct {
	Sheet    string
	Cell     string
	Path     string
	OffsetX  int
	OffsetY  int
}

// 写入excel，为实现多图，不用流式
func WriteExcel(bgsx configs.FormSchema, data GtableDc, rediskey string, pageSize int, zdsz map[string]configs.FieldConfig) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered from panic:", r)
        }
    }()
    if err := os.MkdirAll("uploads/excel", 0755); err != nil {
        fmt.Println("创建目录失败:", err)
        return
    }
    lienum := len(data.Zds)
    file := excelize.NewFile()
    sheet := "Sheet1"
    // 写入表头
    headerRow := make([]interface{}, lienum)
    for i := 0; i < lienum; i++ {
        headerRow[i] = data.Zd[data.Zds[i]]
    }
    if err := file.SetSheetRow(sheet, "A1", &headerRow); err != nil {
        fmt.Println(err)
        return
    }
    var h int = 2 // 从第二行开始写入数据
    var imagesToAdd []ImageInfo
    pages := int(math.Ceil(float64(data.Max) / float64(pageSize)))
    for page := 1; page <= pages; page++ {
        gtable := ChuckTable(data, page, pageSize)
        time.Sleep(time.Millisecond * 100)
        fmt.Println("当前页数", page)
        for x := 0; x < len(gtable); x++ {
            configs.CRdb.Set(rediskey, h, 100 * time.Second) //缓存100秒
            dataRow := make([]interface{}, lienum)
            for i := 0; i < lienum; i++ {
                key := data.Zds[i]
                nr := gtable[x][key]
                nr, imagesToAdd = processData(i, key, nr, zdsz, imagesToAdd, h)
                dataRow[i] = nr
            }
            // 写入数据行
            startCell, _ := excelize.CoordinatesToCellName(1, h)
            if err := file.SetSheetRow(sheet, startCell, &dataRow); err != nil {
                fmt.Println(err)
                return
            }
            h++
        }
    }
    // 添加所有图片（此时所有单元格已存在）
    for _, img := range imagesToAdd {
        fmt.Println("添加图片:", img.Path)
        graphicOptions := &excelize.GraphicOptions{
            AutoFit:  true,
            OffsetX:  img.OffsetX,
            OffsetY:  img.OffsetY,
            Positioning: "absolute", // 确保图片精确定位
        }
        if err := file.AddPicture(img.Sheet, img.Cell, img.Path, graphicOptions); err != nil {
            fmt.Println("添加图片失败:", img.Path, "错误:", err)
        }
    }
    // 阶段一：写入临时文件前，设置状态为 -1 表示开始写入
    configs.CRdb.Set(rediskey, -1, 100*time.Second)
    // 保存到临时文件
    tempPath := "uploads/excel/" + rediskey + "temp.xlsx"
    if err := file.SaveAs(tempPath); err != nil {
        fmt.Printf("文件保存失败 | 临时路径: %s | 错误: %v\n", tempPath, err)
        configs.CRdb.Set(rediskey, -2, 100*time.Second) // 标记为失败状态
        return
    }
    // 阶段二：临时文件写入完成，设置状态为 0 表示等待重命名
    configs.CRdb.Set(rediskey, 0, 100*time.Second)
    // 执行原子性重命名
    finalPath := "uploads/excel/" + rediskey + ".xlsx"
    if err := os.Rename(tempPath, finalPath); err != nil {
        fmt.Printf("文件重命名失败: %v\n", err)
        configs.CRdb.Set(rediskey, -2, 100*time.Second)
        return
    }
    // 阶段三：重命名完成，设置状态为 data.Max+1
    configs.CRdb.Set(rediskey, data.Max+1, 100*time.Second)
}

// 处理单元格数据（修正参数类型并添加h参数）
func processData(i int, key string, nr interface{}, zdsz map[string]configs.FieldConfig, imagesToAdd []ImageInfo, h int) (interface{}, []ImageInfo) {
    if key == "created_at" || key == "updated_at" {
        switch v := nr.(type) {
        case time.Time:
            nr = v.Format("2006-01-02 15:04:05")
        case string:
            if t, err := time.Parse(time.RFC3339, v); err == nil {
                nr = t.Format("2006-01-02 15:04:05")
            }
        case []byte:
            if t, err := time.Parse(time.RFC3339, string(v)); err == nil {
                nr = t.Format("2006-01-02 15:04:05")
            }
        default:
            nr = fmt.Sprintf("%v", nr) // 保底处理
        }
	} else if (zdsz[key].Type == "muselect" || zdsz[key].Type == "checkbox") && nr != "" {
		var nrArray []string
		if err := json.Unmarshal([]byte(nr.(string)), &nrArray); err != nil {
			fmt.Println("Error unmarshalling JSON:", err)
			return nr, imagesToAdd
		}
		nr = strings.Join(nrArray, ",")
	} else if zdsz[key].Type == "image" && nr != "" {
		if str, ok := nr.(string); ok {
			decodedPath, err := url.QueryUnescape(str) // URL 解码，确保中文路径正确
			if err != nil {
				fmt.Println("Error decoding URL:", err)
				return nr, imagesToAdd
			}
			imagePath := strings.TrimPrefix(decodedPath, configs.MyURL) // 去掉 URL 前缀
			cell2, _ := excelize.CoordinatesToCellName(i+1, h) // 使用传入的h
			imagesToAdd = append(imagesToAdd, ImageInfo{
				Sheet:   "Sheet1",
				Cell:    cell2,
				Path:    imagePath,
				OffsetX: 0,
				OffsetY: 0,
			})
			nr = ""
		}
	} else if zdsz[key].Type == "multiimage" && nr != "" {
		if str, ok := nr.(string); ok {
			var urls []string
			if err := json.Unmarshal([]byte(str), &urls); err == nil {
				for idx, imgurl := range urls {
					decodedURL, err := url.QueryUnescape(imgurl)
					if err != nil {
						fmt.Println("Error decoding URL:", err)
						continue
					}
					imagePath := strings.TrimPrefix(decodedURL, configs.MyURL)
					cell2, _ := excelize.CoordinatesToCellName(i+1, h) // 使用传入的h
					imagesToAdd = append(imagesToAdd, ImageInfo{
						Sheet:    "Sheet1",
						Cell:     cell2,
						Path:     imagePath,
						OffsetX:  idx * 50,
						OffsetY:  0,
					})
				}
			}
			nr = ""
		}
	}
	return nr, imagesToAdd
}

// 分块读取数据库
func ChuckTable(data GtableDc, page, pageSize int) ([]map[string]interface{}) {
	var gtable []map[string]interface{}
	cx := configs.DB.Table(data.Bm).Select(data.Zds)
	//是否指定行
	if data.Lx == "selected" {
	    cx.Where("id IN (?)", data.IDS)
	} else if data.Lx == "filter" {
	    //是否有筛选
        for key, item := range data.FilterForm {
            switch item.Operator {
                case "=":
                    cx.Where(key + " = ?", item.Value)
                case "!=":
                    cx.Where(key + " != ?", item.Value)
                case ">":
                    cx.Where(key + " > ?", item.Value)
                case "<":
                    cx.Where(key + " < ?", item.Value)
                case ">=":
                    cx.Where(key + " >= ?", item.Value)
                case "<=":
                    cx.Where(key + " <= ?", item.Value)
                case "in", "noin":
                    var values []string
                    err := json.Unmarshal([]byte(item.Value), &values)
                    if err != nil {
                        continue
                    }
                    if item.Operator == "in" {
                        cx.Where(key + " IN (?)", values)
                    } else {
                        cx.Where(key + " NOT IN (?)", values)
                    }
                case "startend":
                    start, end, layout, err := ParseDateRange(item.Value)
                    if err != "" {
                        continue
                    }
                    fmt.Println(start, end, layout)
                    cx.Where(key + " >= ?", start.Format(layout)).Where(key + " <= ?", end.Format(layout))
            }
        }
	}
	cx.Scopes(configs.Paginate(page, pageSize)).Scan(&gtable)
	return gtable
}

// 轮询
type GtableLx struct {
	RedisKey string `json:"rediskey"`
	Max      int    `json:"max"`
}

// 轮询表格导出进度
func OutExcelJd(c *gin.Context) {
    var data GtableLx
    if err := c.ShouldBindJSON(&data); err != nil {
        JsonResponse(c, http.StatusBadRequest, err.Error(), nil)
        return
    }
    val, found := configs.CRdb.Get(data.RedisKey)
    if !found {
        JsonResponse(c, http.StatusBadRequest, "任务不存在或已过期", nil)
        return
    }
    statusCode := val.(int)
    switch {
    case statusCode == -2:
        JsonResponse(c, http.StatusInternalServerError, "文件生成失败", nil)
    case statusCode == -1:
        JsonResponse(c, http.StatusOK, "文件生成中", 0) // 初始状态
    case statusCode == 0:
        // 检查临时文件是否存在，给前端过渡状态
        tmpPath := "uploads/excel/" + data.RedisKey + "temp.xlsx"
        if _, err := os.Stat(tmpPath); err == nil {
            JsonResponse(c, http.StatusOK, "文件生成中", data.Max) // 伪完成度
        } else {
            JsonResponse(c, http.StatusInternalServerError, "临时文件丢失", nil)
        }
    case statusCode == data.Max+1:
        finalPath := "uploads/excel/" + data.RedisKey + ".xlsx"
        if _, err := os.Stat(finalPath); err == nil {
            JsonResponse(c, http.StatusOK, "完成", statusCode)
        } else {
            JsonResponse(c, http.StatusInternalServerError, "文件不存在", nil)
        }
    default:
        // 正常进度返回
        JsonResponse(c, http.StatusOK, "处理中", statusCode)
    }
}